#include <stdio.h>
#include <intrins.h>
#include <string.h>

#include "stc8h.h"
#include "stc32_stc8_usb.h"

//正常运行时候端口状态
void sys_run(void);
//系统初始化
void sys_init(void);
//读取串口命令
void readCommand(void);


char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

#define PRINTF_HID            //printf输出直接重定向到USB HID接口



//#define MAIN_Fosc        22118400L     //定义主时钟
//#define MAIN_Fosc        12000000L     //定义主时钟
//#define MAIN_Fosc        11059200L     //定义主时钟
//#define MAIN_Fosc         5529600L     //定义主时钟
//#define MAIN_Fosc        24000000UL    //定义主时钟
#define MAIN_Fosc        35000000UL     //定义主时钟

//缓存
#define BUFF_LEN 256

//========================================================================


// CPU D0-D7  P0
// CPU A0-7   P2
// CPU A8-14  P40-46
// CPU_ROMSEL P13
// CPU_RW     P14
// CPU_M2     P37
// PPU D0-7   P6
// PPU A0-7   P7
// PPU A8-12  P50-P54
// PPU A13    P16
// PPU_OE     P15
// PPU_RW     P17
// PPU_RAM10 接 A10-H A110-V

// CPU M2     P37
// CPU_IRQ    P47

#define CPU_M2     P37
#define CPU_IRQ    P47


#define CPU_OE     P10
#define CPU_CE     P13
#define CPU_RW     P14

#define PPU_CE     P16
#define PPU_OE     P15
#define PPU_RW     P17

#define STC_LED    P35


//========================================================================
// 函数: void delay_ms(unsigned int ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-3-9
// 备注: 
//========================================================================
void delay_ms(unsigned int ms)
{
    unsigned int i;
    do{
        i = MAIN_Fosc / 10000;
        while(--i);
    }while(--ms);
}

void delay_us(unsigned int ns)
{
    unsigned int i;
    while(ns)
    {
      i = 10;
      while (i) i--;
      ns--;
    }
}
void delay_50(void)
{
    unsigned int i;
    i = 5;
    while (--i);
}

void delay_100(void)
{
    unsigned int i;
    i = 9;
    while (--i);
}

void delay_500(void)
{
    unsigned int i;
    i = 50;
    while (--i);
}



// ------------------------------------------------

u8 cmd;
u8 chipSelect;
u8 cmdBuffer[22];
u32 chipId=0,startAddr=0,endAddr=0,dataLength=0;
u8 startPage=0,endPage=0;
u8 char1[1];    // 用于输出
u8 is29 = 0;//是否是29芯片
u16 buff = 64;//最大256

u8 out16[16];

xdata u8 pageBuffer[BUFF_LEN];

// 串口收发 参考 https://www.stcaimcu.com/forum.php?mod=viewthread&tid=2392

void usb_sendchar(char c)
{
    char1[0]=c;
    USB_SendData(char1,1);
    usb_OUT_done();
}    

void usb_send(char cs[],int length)
{
    USB_SendData(cs,length);
    usb_OUT_done();
}


//读取写入数据缓存
void readBuffer()
{
    uint8_t i;
    while(1){
      if (bUsbOutReady){
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            pageBuffer[i]=UsbOutBuffer[i];
          }
          usb_OUT_done();
          return;
        }
      }
    }
}



//执行命令缓存
void readCommand(void)
{
    uint8_t i;
    while(1)
    {
      if (bUsbOutReady)
      {
        if(OutNumber>0){
          for(i=0;i<OutNumber;i++){
            cmdBuffer[i]=UsbOutBuffer[i];
          }
          usb_OUT_done();
         return;
        }
      }
    }
}


u8 hexDigit(char c) {
  if      (c >= '0' && c <= '9') 
    return c - '0';
  else if (c >= 'a' && c <= 'f') 
    return c - 'a' + 10;
  else if (c >= 'A' && c <= 'F') 
    return c - 'A' + 10;
  else 
    return 0;
}

u8 hexByte(char *a) {
  return ((hexDigit(a[0])*16) + hexDigit(a[1]));
}


u32 hexChip(char *dat){
  char* p = dat;
  u32 re = 0;
  if(dat[1]>=0x30 && dat[1]<=0x39)
    re+=(dat[1]-0x30)*10000;
  if(dat[2]>=0x30 && dat[2]<=0x39)
    re+=(dat[2]-0x30)*1000;
  if(dat[3]>=0x30 && dat[3]<=0x39)
    re+=(dat[3]-0x30)*100;
  if(dat[4]>=0x30 && dat[4]<=0x39)
    re+=(dat[4]-0x30)*10;
  if(dat[5]>=0x30 && dat[5]<=0x39)
    re+=(dat[5]-0x30)*1;
  return re;
}

u32 hexWord(char *dat) {
  return (
    (hexDigit(dat[0])*4096)+
    (hexDigit(dat[1])*256)+
    (hexDigit(dat[2])*16)+
    (hexDigit(dat[3])));
}


void read_mode_CPU(void){
  // P0 高阻输入
  P0M0 = 0x00; P0M1 = 0xff;
	
  P2M0 = 0xff; P2M1 = 0x00;//推挽
  P4M0 |= 0x7f; P4M1 &= ~0x7f;//P40-46 推挽
	
  P1M0 |= 0x19; P1M1 &= ~0x19;//P10 P13 P14 推挽
	
  CPU_RW = 1;//P14
  CPU_CE = 1;//P13
  CPU_OE = 0;//P10

}
void read_mode_PPU(void){
    // P0 高阻输入
    P6M0 = 0x00; P6M1 = 0xff;
    P5M0 = 0xff; P5M1 = 0x00;//推挽
    P7M0 = 0xff; P7M1 = 0x00;//推挽

    PPU_RW = 1;//P17
    PPU_CE = 1;//P16
    PPU_OE = 0;//P15 OE=0输出
    P1M0 |= 0xe0; P1M1 &= ~0xe0;//P15 P16 P17 推挽
}

void read_mode(void){
    if(chipSelect==1){
        read_mode_CPU();
    }else if(chipSelect==2){
        read_mode_PPU();
    }else{
        read_mode_CPU();
        read_mode_PPU();
    }
}

void write_mode_CPU(void){
  // P0 推挽输出
  P0M0 = 0xff; P0M1 = 0x00;
  P2M0 = 0xff; P2M1 = 0x00;//推挽
  P4M0 |= 0x7f; P4M1 &= ~0x7f;//P40-46 推挽
	
  CPU_OE = 1;//P10
  CPU_RW = 1;//P14
  CPU_CE = 0;//P13
  P1M0 |= 0x19; P1M1 &= ~0x19;//P10 P13 P14 推挽


}
void write_mode_PPU(void){
  // P6 推挽输出
  P6M0 = 0xff; P6M1 = 0x00;
  P5M0 = 0xff; P5M1 = 0x00;//推挽
  P7M0 = 0xff; P7M1 = 0x00;//推挽
  PPU_RW = 1;//P17
  PPU_CE = 0;//P16
  PPU_OE = 1;//P15 OE=1
  P1M0 |= 0xe0; P1M1 &= ~0xe0;//P15 P16 P17 推挽
  //P1M0 &= ~0xe0; P1M1 &= ~0xe0;//P15 P16 P17 双向
}

void write_mode(void){
  if(chipSelect==1){
    write_mode_CPU();
  }else{
    write_mode_PPU();
  }
}

//读数据
u8 read_CPU_data(){
    return P0;
}
u8 read_PPU_data(){
    return P6;
}

//写数据
void write_CPU_data(char dat){
    P0 = dat;
}
void write_PPU_data(char dat){
    P6 = dat;
}

// ---------------------------------------

void setAddressCPU(u32 addr)
{
  P2 = addr & 0xff;
  //P4 = (addr >> 8) & 0x7f | 0x80;//P47 IRQ=1
  P40 = addr >> 8 & 1;
  P41 = addr >> 9 & 1;
  P42 = addr >> 10 & 1;
  P43 = addr >> 11 & 1;
  P44 = addr >> 12 & 1;
  P45 = addr >> 13 & 1;
  P46 = addr >> 14 & 1;
}

void setAddressPPU(u32 addr)
{
  P7 = addr & 0xff;
  P50 = addr >> 8  & 1;
  P51 = addr >> 9  & 1;
  P52 = addr >> 10 & 1;
  P53 = addr >> 11 & 1;
  P54 = addr >> 12 & 1;
}

void setAddress0(){
  setAddressCPU(0);
  setAddressPPU(0);
}

// 根据地址读取数据
u8 readCPUByte(u32 addr){
  setAddressCPU (addr);
  delay_500();
  return read_CPU_data();
}
u8 readPPUByte(u32 addr){
  setAddressPPU (addr);
  delay_100();
  return read_PPU_data();
}

// 读取芯片内容(读取的时候ce oe全部拉低，改变地址就可以输出)
void readBinary(u32 addr, u32 count) {
  u8 i=0;

  if(chipSelect==1){
    read_mode_CPU();
	CPU_RW = 1;
	CPU_OE = 0;
    CPU_CE = 0;
  }else{
    read_mode_PPU();
    PPU_CE = 0;
  }

  delay_ms(10);

  while (count) {
    if(chipSelect==1){
      out16[i]=readCPUByte(addr++);
    }else{
      out16[i]=readPPUByte(addr++);
    }
    if(i++>=15){
      usb_send(out16,16);
      i=0;
    }
    count--;
  }
	
  if(chipSelect==1){
	CPU_RW = 1;
    CPU_CE = 1;
  }else{
    PPU_CE = 1;
  }

}


void check_buff(u32 addr){
  u8 i;
  u8 rd;
  delay_ms(10);
  read_mode();
  //读数据校验
  delay_500();
    
  for(i=0;i<buff;i++){
    if(chipSelect==1){
	  CPU_OE = 0;
      CPU_CE = 0;
      rd=readCPUByte(addr+i);
    }else{
      PPU_CE = 0;
      rd=readPPUByte(addr+i);
    }
    if(pageBuffer[i]!=rd){
			
	  CPU_OE = 1;
      CPU_CE = 1;
      PPU_CE = 1;

      usb_send("error\r\n",7);
      return;
    }
  }
	CPU_OE = 0;
	CPU_RW = 1;
    CPU_CE = 1;
    PPU_OE = 0;
    PPU_CE = 1;
    PPU_RW = 1;
    usb_send("ok\r\n",4);
}



void writeBinary(u32 address, u8 dat){
  if(chipSelect==1){
    write_CPU_data(dat);
    setAddressCPU(address);
    CPU_RW = 0;
    //delay_500();
    delay_us(1);
    CPU_RW = 1;
    delay_us(1);
  }else{
    write_PPU_data(dat);
    setAddressPPU(address);
    PPU_RW = 0;
    delay_100();
    PPU_RW = 1;
  }
}



void writeChip(u32 addr){
  int i=0;

  readBuffer();

  write_mode();

  if(chipSelect==1){
    //无特殊处理
	CPU_OE = 1;
	CPU_CE = 0;
	CPU_RW = 1;
  }else{
	PPU_RW = 1;
    PPU_OE = 1;
    PPU_CE = 0;
  }
  delay_ms(1);

  for(i=0;i<64;i++){
    writeBinary(addr+i,pageBuffer[i]);
  }
	
  read_mode();
  
  delay_500();

  //check_buff(addr);
  usb_send("ok\r\n",4);

}


void main()
{
    sys_init();                                     //管脚初始化
    usb_init();                                     //USB CDC 接口配置
    
    IE2 |= 0x80;                                    //使能USB中断
    EA = 1;

    while (DeviceState != DEVSTATE_CONFIGURED);     //等待USB完成配置

    while (1)
    {

      //亮 待机运行
	  STC_LED = 0;
      readCommand();
      //灭 命令执行
	  STC_LED = 1;
            
      cmd        = cmdBuffer[0];            //指令
      chipSelect = hexDigit(cmdBuffer[1]);            // 1-CPU 2-PPU
      chipId     = hexChip(cmdBuffer+2);    //芯片
      startPage  = hexDigit(cmdBuffer[9]);
      startAddr  = hexWord(cmdBuffer+10);   //开始地址
      endPage    = hexDigit(cmdBuffer[15]);
      endAddr    = hexWord(cmdBuffer+16);   //结束地址
      
      startAddr  &= 0xffff;
      endAddr    &= 0xffff;
      startPage  &= 0xf;
      endPage    &= 0xf;
      endPage     = endPage < startPage ? startPage : endPage;
      
      
      startAddr = (startPage * 65536) + startAddr;
      endAddr   = (endPage   * 65536) + endAddr;
      
      endAddr = endAddr < startAddr ? startAddr : endAddr;


      // 数据长度
      dataLength = endAddr - startAddr + 1;

      switch(cmd){
        
        case 'i':
            usb_send("MAPPER0\r\n",9);
            break;
        
        case 'v':
            usb_send("1.0\r\n",5);
            break;
        
        case 't':
            usb_send("Ready\r\n",7);
            break;

        case 'r':
            readBinary(startAddr, dataLength);
            break;

        case 'w':
            if(chipSelect>0){
              writeChip(startAddr);
              break;
            }else{
              usb_send("Write unsupport\r\n",17);
              break;
            }

        default:    break;
        
      }

      // 端口切换回运行状态
	  sys_run();

    }
}

// 卡带运行使用
void sys_run(void)
{
    // 初始状态 WE 都为高 不受卡带控制
    CPU_RW = 1;//P14
    PPU_RW = 1;//P17
    // 推挽输出
    P1M0 |= 0x90; P1M1 &= ~0x90;

    delay_ms(10);

    // 临时改成高电压，后面全部变成高阻态 P10 P13 P15 P16
    CPU_OE = 1;
    CPU_CE = 1;
    PPU_OE = 1;
    PPU_CE = 1;

    // 除了 P14 P17 都是高阻
    P1M0 &= ~0x6f; P1M1 |= 0x6f; 


    //默认都是 高阻输入 0x00 0xff
    P0M0 = 0x00;   P0M1 = 0xff;
    //P1M0 = 0x00;   P1M1 = 0xff;
    P2M0 = 0x00;   P2M1 = 0xff;
    P3M0 = 0x00;   P3M1 = 0xff;
    P4M0 = 0x00;   P4M1 = 0xff;
    P5M0 = 0x00;   P5M1 = 0xff;
    P6M0 = 0x00;   P6M1 = 0xff;
    P7M0 = 0x00;   P7M1 = 0xff;

    // P35 LED 指示灯亮
    STC_LED = 0;
    // P35 板载LED 推挽输出
    P3M0 |= 0x20; P3M1 &= ~0x20;

}


void sys_init(void)
{
    // 初始化端口
    sys_run();

    P_SW2 |= 0x80;//扩展寄存器(XFR)访问使能

    IRC48MCR = 0x80;//使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));//等待时钟稳定
    
    USBCLK = 0x00;
    USBCON = 0x90;

}


